#ifndef LIMONP_STD_EXTEMSION_HPP
#define LIMONP_STD_EXTEMSION_HPP

#include <map>

#if(__cplusplus == 201103L)
#include <unordered_map>
#include <unordered_set>
#else
#include <tr1/unordered_map>
#include <tr1/unordered_set>
namespace std
{
    using std::tr1::unordered_map;
    using std::tr1::unordered_set;
}

#endif

#include <set>
#include <vector>
#include <fstream>
#include <sstream>


namespace std
{
    template<typename T>
        ostream& operator << (ostream& os, const vector<T>& vec)
        {
            if(vec.empty())
            {
                return os << "[]";
            }
            os<<"[\""<<vec[0];
            for(size_t i = 1; i < vec.size(); i++)
            {
                os<<"\", \""<<vec[i];
            }
            os<<"\"]";
            return os;
        }
    template<class T1, class T2>
        ostream& operator << (ostream& os, const pair<T1, T2>& pr)
        {
            os << pr.first << ":" << pr.second ;
            return os;
        }


    template<class T>
        string& operator << (string& str, const T& obj)
        {
            stringstream ss;
            ss << obj; // call ostream& operator << (ostream& os,
            return str = ss.str();
        }

    template<class T1, class T2>
        ostream& operator << (ostream& os, const map<T1, T2>& mp)
        {
            if(mp.empty())
            {
                os<<"{}";
                return os;
            }
            os<<'{';
            typename map<T1, T2>::const_iterator it = mp.begin();
            os<<*it;
            it++;
            while(it != mp.end())
            {
                os<<", "<<*it;
                it++;
            }
            os<<'}';
            return os;
        }
    template<class T1, class T2>
        ostream& operator << (ostream& os, const std::unordered_map<T1, T2>& mp)
        {
            if(mp.empty())
            {
                return os << "{}";
            }
            os<<'{';
            typename std::unordered_map<T1, T2>::const_iterator it = mp.begin();
            os<<*it;
            it++;
            while(it != mp.end())
            {
                os<<", "<<*it++;
            }
            return os<<'}';
        }

    template<class T>
        ostream& operator << (ostream& os, const set<T>& st)
        {
            if(st.empty())
            {
                os << "{}";
                return os;
            }
            os<<'{';
            typename set<T>::const_iterator it = st.begin();
            os<<*it;
            it++;
            while(it != st.end())
            {
                os<<", "<<*it;
                it++;
            }
            os<<'}';
            return os;
        }

    template<class KeyType, class ContainType>
        bool isIn(const ContainType& contain, const KeyType& key)
        {
            return contain.end() != contain.find(key);
        }

    template<class T>
        basic_string<T> & operator << (basic_string<T> & s, ifstream & ifs)
        {
            return s.assign((istreambuf_iterator<T>(ifs)), istreambuf_iterator<T>());
        }

    template<class T>
        ofstream & operator << (ofstream & ofs, const basic_string<T>& s)
        {
            ostreambuf_iterator<T> itr (ofs);
            copy(s.begin(), s.end(), itr);
            return ofs;
        }
}

#endif
